/**
 * ToolBall 工具球组件
 * 一个功能丰富的 JavaScript 组件，用于在网页中快速创建工具球和工具面板
 * 支持拖拽、工具管理、弹窗交互等功能
 */

(function(global) {
  'use strict';

  // ==================== 样式定义 ====================

  const TOOLBALL_STYLES = `
  /* 工具球样式 */
  .tool-ball {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(74, 144, 226, 0.8), rgba(74, 144, 226, 0.6));
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    cursor: move;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-weight: bold;
    font-size: 16px;
    user-select: none;
    transition: all 0.2s ease;
  }

  .tool-ball:hover {
    transform: translateY(-50%) scale(1.05);
  }

  .tool-ball.dragging {
    cursor: grabbing;
    transform: translateY(-50%) scale(1.1);
  }

  /* 工具面板样式 */
  .tool-panel {
    width: 200px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    position: fixed;
    z-index: 9998;
    transition: transform 0.1s ease-out;
    max-height: 400px;
    overflow-y: auto;
    padding: 8px;
  }

  .tool-panel.hidden {
    transform: translateX(120%);
    opacity: 0;
    pointer-events: none;
  }

  /* 工具分组样式 */
  .tool-group {
    margin-bottom: 8px;
  }

  .tool-group-title {
    font-size: 12px;
    color: #666;
    padding: 4px 8px;
    margin-bottom: 4px;
    font-weight: 500;
  }

  .tool-group-title:not(:first-child) {
    margin-top: 8px;
    border-top: 1px solid #f0f0f0;
    padding-top: 8px;
  }

  /* 工具按钮基础样式 */
  .tool-item {
    height: 32px;
    padding: 0 12px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    gap: 10px;
    border: none;
    cursor: pointer;
    transition: all 0.2s ease;
    margin-bottom: 4px;
    background: transparent;
    font-size: 14px;
    color: #333;
  }

  .tool-item:hover {
    background: #f5f5f5;
  }

  .tool-item:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .tool-item:disabled:hover {
    background: transparent;
  }

  .tool-icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
  }

  .tool-label {
    flex: 1;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* 开关工具样式 */
  .tool-switch {
    position: relative;
    width: 44px;
    height: 24px;
    background: #ccc;
    border-radius: 12px;
    transition: background 0.2s ease;
    flex-shrink: 0;
  }

  .tool-switch.active {
    background: #4A90E2;
  }

  .tool-switch-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background: white;
    border-radius: 50%;
    transition: transform 0.2s ease;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  }

  .tool-switch.active .tool-switch-thumb {
    transform: translateX(20px);
  }

  /* 下拉选择工具样式 */
  .tool-select {
    flex: 1;
    height: 24px;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 0 8px;
    font-size: 12px;
    background: white;
    cursor: pointer;
    outline: none;
  }

  .tool-select:hover {
    border-color: #4A90E2;
  }

  .tool-select:focus {
    border-color: #4A90E2;
    box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2);
  }

  /* 滑块工具样式 */
  .tool-slider-container {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .tool-slider {
    flex: 1;
    height: 4px;
    background: #ddd;
    border-radius: 2px;
    outline: none;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
  }

  .tool-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background: #4A90E2;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  }

  .tool-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: #4A90E2;
    border-radius: 50%;
    cursor: pointer;
    border: none;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  }

  .tool-slider-value {
    font-size: 12px;
    color: #666;
    min-width: 30px;
    text-align: right;
  }

  /* 文本框工具样式 */
  .tool-text-input {
    flex: 1;
    height: 24px;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 0 8px;
    font-size: 12px;
    background: white;
    outline: none;
  }

  .tool-text-input:hover {
    border-color: #4A90E2;
  }

  .tool-text-input:focus {
    border-color: #4A90E2;
    box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2);
  }

  /* 滚动条样式 */
  .tool-panel::-webkit-scrollbar {
    width: 6px;
  }

  .tool-panel::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }

  .tool-panel::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;
  }

  .tool-panel::-webkit-scrollbar-thumb:hover {
    background: #a8a8a8;
  }
`;

  // ==================== 事件系统 ====================

  class EventEmitter {
  constructor() {
    this.eventListeners = new Map();
  }

  /**
   * 监听事件
   * @param {string} event - 事件名称
   * @param {Function} callback - 回调函数
   */
  on(event, callback) {
    if (!this.eventListeners.has(event)) {
      this.eventListeners.set(event, []);
    }
    this.eventListeners.get(event).push(callback);
  }

  /**
   * 移除事件监听
   * @param {string} event - 事件名称
   * @param {Function} callback - 回调函数
   */
  off(event, callback) {
    if (this.eventListeners.has(event)) {
      const callbacks = this.eventListeners.get(event);
      const index = callbacks.indexOf(callback);
      if (index > -1) {
        callbacks.splice(index, 1);
      }
    }
  }

  /**
   * 触发事件
   * @param {string} event - 事件名称
   * @param {*} data - 事件数据
   */
  emit(event, data) {
    if (this.eventListeners.has(event)) {
      this.eventListeners.get(event).forEach(callback => {
        try {
          callback(data);
        } catch (error) {
          console.error(`Error in event listener for ${event}:`, error);
        }
      });
    }
  }

  /**
   * 移除所有事件监听
   */
  removeAllListeners() {
    this.eventListeners.clear();
  }
}

  // ==================== 拖拽处理器 ====================

  class DragHandler {
  constructor(element, options = {}) {
    this.element = element;
    this.isDragging = false;
    this.startX = 0;
    this.startY = 0;
    this.startLeft = 0;
    this.startTop = 0;
    this.callbacks = {
      onDragStart: options.onDragStart || (() => {}),
      onDrag: options.onDrag || (() => {}),
      onDragEnd: options.onDragEnd || (() => {})
    };

    this.init();
  }

  init() {
    this.element.addEventListener('mousedown', this.handleMouseDown.bind(this));
    document.addEventListener('mousemove', this.handleMouseMove.bind(this));
    document.addEventListener('mouseup', this.handleMouseUp.bind(this));
  }

  handleMouseDown(e) {
    e.preventDefault();
    this.isDragging = true;
    this.startX = e.clientX;
    this.startY = e.clientY;
    
    const rect = this.element.getBoundingClientRect();
    this.startLeft = rect.left;
    this.startTop = rect.top;

    this.element.classList.add('dragging');
    this.callbacks.onDragStart(e);
  }

  handleMouseMove(e) {
    if (!this.isDragging) return;

    const deltaX = e.clientX - this.startX;
    const deltaY = e.clientY - this.startY;
    
    const newLeft = this.startLeft + deltaX;
    const newTop = this.startTop + deltaY;

    // 边界检测
    const maxLeft = window.innerWidth - this.element.offsetWidth;
    const maxTop = window.innerHeight - this.element.offsetHeight;

    const constrainedLeft = Math.max(0, Math.min(newLeft, maxLeft));
    const constrainedTop = Math.max(0, Math.min(newTop, maxTop));

    this.element.style.left = `${constrainedLeft}px`;
    this.element.style.top = `${constrainedTop}px`;
    this.element.style.right = 'auto';

    this.callbacks.onDrag(e, {
      left: constrainedLeft,
      top: constrainedTop,
      deltaX,
      deltaY
    });
  }

  handleMouseUp(e) {
    if (!this.isDragging) return;

    this.isDragging = false;
    this.element.classList.remove('dragging');

    // 检查应该吸附到哪一侧
    const rect = this.element.getBoundingClientRect();
    const centerX = rect.left + rect.width / 2;
    const screenCenterX = window.innerWidth / 2;
    
    // 根据中心点位置决定吸附到左侧还是右侧
    const shouldSnapToLeft = centerX < screenCenterX;
    const shouldSnapToRight = centerX >= screenCenterX;

    if (shouldSnapToLeft) {
      // 吸附到左侧，保持当前垂直位置
      this.element.style.left = '0';
      this.element.style.right = 'auto';
      // 不修改 top 值，保持拖拽时的垂直位置
    } else if (shouldSnapToRight) {
      // 吸附到右侧，保持当前垂直位置
      this.element.style.right = '0';
      this.element.style.left = 'auto';
      // 不修改 top 值，保持拖拽时的垂直位置
    }

    this.callbacks.onDragEnd(e, {
      shouldSnapToLeft,
      shouldSnapToRight,
      finalPosition: {
        left: this.element.style.left,
        top: this.element.style.top,
        right: this.element.style.right
      }
    });
  }

  destroy() {
    this.element.removeEventListener('mousedown', this.handleMouseDown.bind(this));
    document.removeEventListener('mousemove', this.handleMouseMove.bind(this));
    document.removeEventListener('mouseup', this.handleMouseUp.bind(this));
  }
}

  // ==================== 工具基类 ====================

  class BaseTool extends EventEmitter {
  constructor(config) {
    super();
    this.id = config.id;
    this.name = config.name;
    this.config = config;
    this.enabled = config.enabled !== false;
    this.element = null;
    this.group = config.group || 'default';
  }

  /**
   * 生命周期钩子 - 创建时
   */
  onCreate() {
    // 子类实现
  }

  /**
   * 生命周期钩子 - 销毁时
   */
  onDestroy() {
    // 子类实现
  }

  /**
   * 渲染工具
   * @returns {HTMLElement} DOM元素
   */
  render() {
    throw new Error('render method must be implemented');
  }

  /**
   * 设置启用/禁用状态
   * @param {boolean} enabled - 是否启用
   */
  setEnabled(enabled) {
    this.enabled = enabled;
    if (this.element) {
      this.element.disabled = !enabled;
    }
  }

  /**
   * 获取工具配置
   */
  getConfig() {
    return { ...this.config };
  }

  /**
   * 更新工具配置
   * @param {Object} updates - 更新配置
   */
  updateConfig(updates) {
    Object.assign(this.config, updates);
    if (this.element) {
      this.render();
    }
  }

  /**
   * 销毁工具
   */
  destroy() {
    this.onDestroy();
    if (this.element && this.element.parentNode) {
      this.element.parentNode.removeChild(this.element);
    }
    this.removeAllListeners();
  }
}

  // ==================== 按钮工具 ====================

  class ButtonTool extends BaseTool {
  constructor(config) {
    super(config);
    this.icon = config.icon || '';
    this.onClick = config.onClick || (() => {});
  }

  onCreate() {
    console.log(`Button tool "${this.name}" created`);
  }

  onDestroy() {
    console.log(`Button tool "${this.name}" destroyed`);
  }

  render() {
    const button = document.createElement('button');
    button.className = 'tool-item';
    button.disabled = !this.enabled;
    
    const iconSpan = document.createElement('span');
    iconSpan.className = 'tool-icon';
    iconSpan.textContent = this.icon;

    const labelSpan = document.createElement('span');
    labelSpan.className = 'tool-label';
    labelSpan.textContent = this.name;

    button.appendChild(iconSpan);
    button.appendChild(labelSpan);

    button.addEventListener('click', async (e) => {
      e.preventDefault();
      if (this.enabled && this.onClick) {
        try {
          await this.onClick();
          this.emit('click');
        } catch (error) {
          console.error(`Error in button tool "${this.name}":`, error);
          this.emit('error', error);
        }
      }
    });

    this.element = button;
    return button;
  }

  /**
   * 触发点击
   */
  async click() {
    if (this.enabled && this.onClick) {
      await this.onClick();
      this.emit('click');
    }
  }
}

  // ==================== 开关工具 ====================

  class SwitchTool extends BaseTool {
  constructor(config) {
    super(config);
    this.value = config.defaultValue || false;
    this.onChange = config.onChange || (() => {});
  }

  onCreate() {
    console.log(`Switch tool "${this.name}" created with value: ${this.value}`);
  }

  onDestroy() {
    console.log(`Switch tool "${this.name}" destroyed`);
  }

  render() {
    const container = document.createElement('div');
    container.className = 'tool-item';
    container.style.cursor = this.enabled ? 'pointer' : 'not-allowed';

    const labelSpan = document.createElement('span');
    labelSpan.className = 'tool-label';
    labelSpan.textContent = this.name;

    const switchContainer = document.createElement('div');
    switchContainer.className = `tool-switch ${this.value ? 'active' : ''}`;

    const thumb = document.createElement('div');
    thumb.className = 'tool-switch-thumb';

    switchContainer.appendChild(thumb);
    container.appendChild(labelSpan);
    container.appendChild(switchContainer);

    if (this.enabled) {
      container.addEventListener('click', (e) => {
        e.preventDefault();
        this.toggle();
      });
    }

    this.element = container;
    return container;
  }

  /**
   * 切换开关状态
   */
  toggle() {
    this.setValue(!this.value);
  }

  /**
   * 设置开关状态
   * @param {boolean} value - 开关状态
   */
  setValue(value) {
    const oldValue = this.value;
    this.value = Boolean(value);
    
    if (this.element) {
      const switchEl = this.element.querySelector('.tool-switch');
      if (switchEl) {
        switchEl.classList.toggle('active', this.value);
      }
    }

    if (oldValue !== this.value) {
      this.onChange(this.value);
      this.emit('change', this.value);
    }
  }

  /**
   * 获取开关状态
   * @returns {boolean} 开关状态
   */
  getValue() {
    return this.value;
  }
}

  // ==================== 下拉选择工具 ====================

  class SelectTool extends BaseTool {
  constructor(config) {
    super(config);
    this.options = config.options || [];
    this.value = config.defaultValue || (this.options[0]?.value || '');
    this.onChange = config.onChange || (() => {});
  }

  onCreate() {
    console.log(`Select tool "${this.name}" created with value: ${this.value}`);
  }

  onDestroy() {
    console.log(`Select tool "${this.name}" destroyed`);
  }

  render() {
    const container = document.createElement('div');
    container.className = 'tool-item';
    container.style.padding = '4px 12px';

    const labelSpan = document.createElement('span');
    labelSpan.className = 'tool-label';
    labelSpan.textContent = this.name;
    labelSpan.style.marginBottom = '4px';
    labelSpan.style.display = 'block';

    const select = document.createElement('select');
    select.className = 'tool-select';
    select.disabled = !this.enabled;

    // 添加选项
    this.options.forEach(option => {
      const optionEl = document.createElement('option');
      optionEl.value = option.value;
      optionEl.textContent = option.label || option.value;
      select.appendChild(optionEl);
    });

    select.value = this.value;

    select.addEventListener('change', (e) => {
      const oldValue = this.value;
      this.value = e.target.value;
      
      if (oldValue !== this.value) {
        this.onChange(this.value);
        this.emit('change', this.value);
      }
    });

    container.appendChild(labelSpan);
    container.appendChild(select);

    this.element = container;
    return container;
  }

  /**
   * 设置选择值
   * @param {string} value - 选择的值
   */
  setValue(value) {
    const oldValue = this.value;
    this.value = value;
    
    if (this.element) {
      const select = this.element.querySelector('.tool-select');
      if (select) {
        select.value = value;
      }
    }

    if (oldValue !== this.value) {
      this.onChange(this.value);
      this.emit('change', this.value);
    }
  }

  /**
   * 获取选择值
   * @returns {string} 选择的值
   */
  getValue() {
    return this.value;
  }
}

  // ==================== 滑块工具 ====================

  class SliderTool extends BaseTool {
  constructor(config) {
    super(config);
    this.min = config.min || 0;
    this.max = config.max || 100;
    this.step = config.step || 1;
    this.value = config.defaultValue || this.min;
    this.onChange = config.onChange || (() => {});
  }

  onCreate() {
    console.log(`Slider tool "${this.name}" created with value: ${this.value}`);
  }

  onDestroy() {
    console.log(`Slider tool "${this.name}" destroyed`);
  }

  render() {
    const container = document.createElement('div');
    container.className = 'tool-item';
    container.style.padding = '4px 12px';

    const labelSpan = document.createElement('span');
    labelSpan.className = 'tool-label';
    labelSpan.textContent = this.name;
    labelSpan.style.marginBottom = '4px';
    labelSpan.style.display = 'block';

    const sliderContainer = document.createElement('div');
    sliderContainer.className = 'tool-slider-container';

    const slider = document.createElement('input');
    slider.type = 'range';
    slider.className = 'tool-slider';
    slider.min = this.min;
    slider.max = this.max;
    slider.step = this.step;
    slider.value = this.value;
    slider.disabled = !this.enabled;

    const valueSpan = document.createElement('span');
    valueSpan.className = 'tool-slider-value';
    valueSpan.textContent = this.value;

    slider.addEventListener('input', (e) => {
      const oldValue = this.value;
      this.value = Number(e.target.value);
      valueSpan.textContent = this.value;
      
      if (oldValue !== this.value) {
        this.onChange(this.value);
        this.emit('change', this.value);
      }
    });

    sliderContainer.appendChild(slider);
    sliderContainer.appendChild(valueSpan);
    container.appendChild(labelSpan);
    container.appendChild(sliderContainer);

    this.element = container;
    return container;
  }

  /**
   * 设置滑块值
   * @param {number} value - 滑块值
   */
  setValue(value) {
    const oldValue = this.value;
    this.value = Math.max(this.min, Math.min(this.max, Number(value)));
    
    if (this.element) {
      const slider = this.element.querySelector('.tool-slider');
      const valueSpan = this.element.querySelector('.tool-slider-value');
      if (slider) {
        slider.value = this.value;
      }
      if (valueSpan) {
        valueSpan.textContent = this.value;
      }
    }

    if (oldValue !== this.value) {
      this.onChange(this.value);
      this.emit('change', this.value);
    }
  }

  /**
   * 获取滑块值
   * @returns {number} 滑块值
   */
  getValue() {
    return this.value;
  }
}

  // ==================== 文本框工具 ====================

  class TextTool extends BaseTool {
  constructor(config) {
    super(config);
    this.value = config.defaultValue || '';
    this.placeholder = config.placeholder || '';
    this.maxLength = config.maxLength || null;
    this.onChange = config.onChange || (() => {});
  }

  onCreate() {
    console.log(`Text tool "${this.name}" created with value: "${this.value}"`);
  }

  onDestroy() {
    console.log(`Text tool "${this.name}" destroyed`);
  }

  render() {
    const container = document.createElement('div');
    container.className = 'tool-item';
    container.style.padding = '4px 12px';

    const labelSpan = document.createElement('span');
    labelSpan.className = 'tool-label';
    labelSpan.textContent = this.name;
    labelSpan.style.marginBottom = '4px';
    labelSpan.style.display = 'block';

    const input = document.createElement('input');
    input.type = 'text';
    input.className = 'tool-text-input';
    input.value = this.value;
    input.placeholder = this.placeholder;
    input.disabled = !this.enabled;
    
    if (this.maxLength) {
      input.maxLength = this.maxLength;
    }

    input.addEventListener('input', (e) => {
      const oldValue = this.value;
      this.value = e.target.value;
      
      if (oldValue !== this.value) {
        this.onChange(this.value);
        this.emit('change', this.value);
      }
    });

    container.appendChild(labelSpan);
    container.appendChild(input);

    this.element = container;
    return container;
  }

  /**
   * 设置文本框值
   * @param {string} value - 文本框值
   */
  setValue(value) {
    const oldValue = this.value;
    this.value = String(value || '');
    
    if (this.element) {
      const input = this.element.querySelector('.tool-text-input');
      if (input) {
        input.value = this.value;
      }
    }

    if (oldValue !== this.value) {
      this.onChange(this.value);
      this.emit('change', this.value);
    }
  }

  /**
   * 获取文本框值
   * @returns {string} 文本框值
   */
  getValue() {
    return this.value;
  }
}

  // ==================== 工具面板 ====================

  class ToolPanel extends EventEmitter {
  constructor(container, ballElement, options = {}) {
    super();
    this.container = container;
    this.ballElement = ballElement; // 添加工具球元素引用
    this.options = {
      width: options.width || 200,
      layout: options.layout || 'list',
      groups: options.groups !== false
    };
    this.tools = new Map();
    this.element = null;
    this.isVisible = false;
    this.groupedTools = new Map();

    this.init();
  }

  init() {
    this.createElement();
    this.setupEventListeners();
  }

  createElement() {
    this.element = document.createElement('div');
    this.element.className = 'tool-panel hidden';
    this.element.style.width = `${this.options.width}px`;
    
    // 阻止面板内的点击事件冒泡，防止外部点击关闭面板
    this.element.addEventListener('click', (e) => {
      e.stopPropagation();
    });
    
    this.container.appendChild(this.element);
  }

  setupEventListeners() {
    // 使用更简单的方法处理点击外部区域关闭面板
    setTimeout(() => {
      document.addEventListener('click', (e) => {
        if (this.isVisible) {
          // 检查点击是否在面板内部 - 使用 Shadow DOM 兼容的方法
          let isInsidePanel = false;
          if (this.element) {
            // 检查点击目标是否在面板的 Shadow DOM 内
            const shadowRoot = this.element.getRootNode();
            if (shadowRoot === document) {
              // 如果面板在普通 DOM 中
              isInsidePanel = this.element.contains(e.target);
            } else {
              // 如果面板在 Shadow DOM 中，检查点击目标是否在同一个 Shadow DOM 中
              const targetRoot = e.target.getRootNode();
              if (targetRoot === shadowRoot) {
                isInsidePanel = this.element.contains(e.target);
              }
            }
          }
          
          // 检查点击是否在工具球内部
          let isInsideBall = false;
          if (this.ballElement) {
            const ballShadowRoot = this.ballElement.getRootNode();
            const targetRoot = e.target.getRootNode();
            if (targetRoot === ballShadowRoot) {
              isInsideBall = this.ballElement.contains(e.target);
            }
          }
          
          // 如果点击既不在面板内，也不在工具球内，则隐藏面板
          if (!isInsidePanel && !isInsideBall) {
            this.hide();
          }
        }
      });
    }, 100);
  }

  /**
   * 添加工具
   * @param {BaseTool} tool - 工具实例
   */
  addTool(tool) {
    this.tools.set(tool.id, tool);
    this.groupTools();
    this.render();
    this.emit('tool:added', tool);
  }

  /**
   * 移除工具
   * @param {string} toolId - 工具ID
   */
  removeTool(toolId) {
    const tool = this.tools.get(toolId);
    if (tool) {
      tool.destroy();
      this.tools.delete(toolId);
      this.groupTools();
      this.render();
      this.emit('tool:removed', toolId);
    }
  }

  /**
   * 更新工具
   * @param {string} toolId - 工具ID
   * @param {Object} updates - 更新配置
   */
  updateTool(toolId, updates) {
    const tool = this.tools.get(toolId);
    if (tool) {
      tool.updateConfig(updates);
      this.groupTools();
      this.render();
      this.emit('tool:updated', tool);
    }
  }

  /**
   * 获取工具
   * @param {string} toolId - 工具ID
   * @returns {BaseTool} 工具实例
   */
  getTool(toolId) {
    return this.tools.get(toolId);
  }

  /**
   * 按分组组织工具
   */
  groupTools() {
    this.groupedTools.clear();
    
    this.tools.forEach(tool => {
      const group = tool.group || 'default';
      if (!this.groupedTools.has(group)) {
        this.groupedTools.set(group, []);
      }
      this.groupedTools.get(group).push(tool);
    });
  }

  /**
   * 渲染面板
   */
  render() {
    this.element.innerHTML = '';

    this.groupedTools.forEach((tools, groupName) => {
      // 创建分组
      const groupEl = document.createElement('div');
      groupEl.className = 'tool-group';

      // 添加分组标题（非默认分组）
      if (groupName !== 'default' && this.options.groups) {
        const titleEl = document.createElement('div');
        titleEl.className = 'tool-group-title';
        titleEl.textContent = groupName;
        groupEl.appendChild(titleEl);
      }

      // 添加工具
      tools.forEach(tool => {
        const toolEl = tool.render();
        groupEl.appendChild(toolEl);
      });

      this.element.appendChild(groupEl);
    });
  }

  /**
   * 显示面板
   */
  show() {
    this.isVisible = true;
    this.updatePosition();
    this.element.classList.remove('hidden');
    this.emit('show');
  }

  /**
   * 更新面板位置，根据工具球位置智能定位
   */
  updatePosition() {
    if (!this.ballElement || !this.element) return;

    const ballRect = this.ballElement.getBoundingClientRect();
    const panelWidth = this.options.width;
    const panelHeight = this.element.offsetHeight || 200; // 预估高度
    const margin = 5; // 减少间距，让面板更贴近工具球

    // 判断工具球在屏幕的哪一侧
    const screenCenterX = window.innerWidth / 2;
    const ballCenterX = ballRect.left + ballRect.width / 2;
    const isOnLeft = ballCenterX < screenCenterX;

    // 计算水平位置
    let left, right;
    if (isOnLeft) {
      // 工具球在左侧，面板向右弹出
      left = `${ballRect.right + margin}px`;
      right = 'auto';
    } else {
      // 工具球在右侧，面板向左弹出
      left = `${ballRect.left - panelWidth - margin}px`;
      right = 'auto';
    }

    // 计算垂直位置，与工具球中心对齐
    const ballCenterY = ballRect.top + ballRect.height / 2;
    let top = ballCenterY;
    const maxTop = window.innerHeight - panelHeight;
    const minTop = 0;
    
    // 如果面板会超出视窗底部，向上调整
    if (top + panelHeight > window.innerHeight) {
      top = Math.max(minTop, window.innerHeight - panelHeight);
    }
    
    // 如果面板会超出视窗顶部，向下调整
    if (top < minTop) {
      top = minTop;
    }

    // 应用位置
    this.element.style.left = left;
    this.element.style.right = right;
    this.element.style.top = `${top}px`;
    this.element.style.transform = 'none'; // 移除默认的 transform
  }

  /**
   * 隐藏面板
   */
  hide() {
    this.isVisible = false;
    this.element.classList.add('hidden');
    this.emit('hide');
  }

  /**
   * 切换面板显示状态
   */
  toggle() {
    if (this.isVisible) {
      this.hide();
    } else {
      this.show();
    }
  }

  /**
   * 销毁面板
   */
  destroy() {
    this.tools.forEach(tool => tool.destroy());
    this.tools.clear();
    this.groupedTools.clear();
    
    if (this.element && this.element.parentNode) {
      this.element.parentNode.removeChild(this.element);
    }
    
    this.removeAllListeners();
  }
}

  // ==================== 工具球主类 ====================

  class ToolBall extends EventEmitter {
  constructor() {
    super();
    this.config = {};
    this.panel = null;
    this.dragHandler = null;
    this.isVisible = false;
    this.container = null;
    this.shadowRoot = null;
    this.ballElement = null;
    this.panelContainer = null;
    
    // 数据保存功能相关属性
    this.data = {}; // 数据对象
    this.storageKey = null; // localStorage键名
    this.autoSaveEnabled = true; // 自动保存开关

    this.initShadowDOM();
  }

  initShadowDOM() {
    // 创建容器元素
    this.container = document.createElement('div');
    this.container.style.position = 'fixed';
    this.container.style.top = '0';
    this.container.style.left = '0';
    this.container.style.width = '100%';
    this.container.style.height = '100%';
    this.container.style.pointerEvents = 'none';
    this.container.style.zIndex = '9997';

    // 创建 Shadow DOM
    this.shadowRoot = this.container.attachShadow({ mode: 'open' });

    // 创建样式表
    const style = document.createElement('style');
    style.textContent = TOOLBALL_STYLES;

    // 创建工具球元素
    this.ballElement = document.createElement('div');
    this.ballElement.className = 'tool-ball';
    this.ballElement.textContent = 'T';
    this.ballElement.style.pointerEvents = 'auto';

    // 创建面板容器
    this.panelContainer = document.createElement('div');
    this.panelContainer.style.position = 'fixed';
    this.panelContainer.style.top = '0';
    this.panelContainer.style.left = '0';
    this.panelContainer.style.width = '0';
    this.panelContainer.style.height = '0';
    this.panelContainer.style.pointerEvents = 'auto';
    this.panelContainer.style.zIndex = '9997';

    // 将元素添加到 Shadow DOM
    this.shadowRoot.appendChild(style);
    this.shadowRoot.appendChild(this.ballElement);
    this.shadowRoot.appendChild(this.panelContainer);

    // 将容器添加到 body
    document.body.appendChild(this.container);
  }

  /**
   * 初始化工具球配置
   * @param {Object} config - 配置对象
   */
  init(config) {
    this.config = config;
    
    // 初始化数据保存功能
    this.storageKey = `toolball_${config.ball?.id || 'default'}`;
    
    // 从localStorage加载数据
    this.loadFromStorage();
    
    // 监听页面卸载事件，自动保存数据
    window.addEventListener('beforeunload', () => {
      this.saveToStorage();
    });
    
    // 设置工具球名称
    if (config.ball?.name) {
      this.ballElement.textContent = config.ball.name.charAt(0).toUpperCase();
    }

    // 初始化面板
    this.panel = new ToolPanel(this.panelContainer, this.ballElement, config.panel || {});
    
    // 设置拖拽处理器
    this.dragHandler = new DragHandler(this.ballElement, {
      onDragStart: () => {
        this.ballElement.style.transform = 'translateY(-50%) scale(1.1)';
      },
      onDragEnd: (e, data) => {
        // 根据吸附位置设置不同的 transform
        if (data && data.shouldSnapToLeft) {
          // 吸附到左侧，只恢复缩放，不强制垂直居中
          this.ballElement.style.transform = 'scale(1)';
        } else if (data && data.shouldSnapToRight) {
          // 吸附到右侧，只恢复缩放，不强制垂直居中
          this.ballElement.style.transform = 'scale(1)';
        } else {
          // 如果不在边缘，保持当前位置，只恢复缩放
          this.ballElement.style.transform = 'scale(1)';
        }
      }
    });

    // 设置点击事件
    this.ballElement.addEventListener('click', (e) => {
      e.stopPropagation();
      this.panel.toggle();
    });

    // 监听面板事件
    this.panel.on('show', () => {
      this.emit('panel:show');
    });

    this.panel.on('hide', () => {
      this.emit('panel:hide');
    });
  }

  /**
   * 显示工具球
   */
  show() {
    this.isVisible = true;
    this.container.style.display = 'block';
    this.emit('show');
  }

  /**
   * 隐藏工具球
   */
  hide() {
    this.isVisible = false;
    this.container.style.display = 'none';
    this.panel.hide();
    this.emit('hide');
  }

  /**
   * 添加工具
   * @param {string} type - 工具类型
   * @param {Object} config - 工具配置
   * @returns {BaseTool} 工具实例
   */
  addTool(type, config) {
    let tool;
    
    switch (type) {
      case 'button':
        tool = new ButtonTool(config);
        break;
      case 'switch':
        tool = new SwitchTool(config);
        break;
      case 'select':
        tool = new SelectTool(config);
        break;
      case 'slider':
        tool = new SliderTool(config);
        break;
      case 'text':
        tool = new TextTool(config);
        break;
      default:
        throw new Error(`Unknown tool type: ${type}`);
    }

    tool.onCreate();
    
    // 如果是数据工具，自动绑定到data对象
    if (['switch', 'select', 'slider', 'text'].includes(type)) {
      this.bindToolToData(tool, config);
    }
    
    this.panel.addTool(tool);
    this.emit('tool:added', tool);
    
    return tool;
  }

  /**
   * 移除工具
   * @param {string} toolId - 工具ID
   */
  removeTool(toolId) {
    this.panel.removeTool(toolId);
    this.emit('tool:removed', toolId);
  }

  /**
   * 更新工具
   * @param {string} toolId - 工具ID
   * @param {Object} updates - 更新配置
   */
  updateTool(toolId, updates) {
    this.panel.updateTool(toolId, updates);
    this.emit('tool:updated', toolId);
  }

  /**
   * 获取工具
   * @param {string} toolId - 工具ID
   * @returns {BaseTool} 工具实例
   */
  getTool(toolId) {
    return this.panel.getTool(toolId);
  }

  /**
   * 获取数据
   * @param {string} key - 数据键名，不传则返回所有数据
   * @returns {*} 数据值或数据对象
   */
  getData(key) {
    if (key) {
      return this.data[key];
    }
    return { ...this.data };
  }

  /**
   * 设置数据
   * @param {string} key - 数据键名
   * @param {*} value - 数据值
   */
  setData(key, value) {
    const oldValue = this.data[key];
    this.data[key] = value;
    
    // 触发数据变化事件
    this.emit('data:change', key, value, oldValue);
    
    // 自动保存到localStorage
    if (this.autoSaveEnabled) {
      this.saveToStorage();
    }
  }

  /**
   * 保存数据到localStorage
   */
  saveToStorage() {
    try {
      localStorage.setItem(this.storageKey, JSON.stringify(this.data));
      this.emit('data:saved', this.data);
    } catch (error) {
      console.error('保存数据到localStorage失败:', error);
      this.emit('data:saveError', error);
    }
  }

  /**
   * 从localStorage加载数据
   */
  loadFromStorage() {
    try {
      const stored = localStorage.getItem(this.storageKey);
      if (stored) {
        this.data = JSON.parse(stored);
        this.emit('data:loaded', this.data);
      }
    } catch (error) {
      console.error('从localStorage加载数据失败:', error);
      this.emit('data:loadError', error);
    }
  }

  /**
   * 清除所有数据
   */
  clearData() {
    this.data = {};
    try {
      localStorage.removeItem(this.storageKey);
      this.emit('data:cleared');
    } catch (error) {
      console.error('清除localStorage数据失败:', error);
    }
  }

  /**
   * 绑定工具到数据对象
   * @param {BaseTool} tool - 工具实例
   * @param {Object} config - 工具配置
   */
  bindToolToData(tool, config) {
    const toolId = config.id;
    
    // 从data对象恢复工具值
    if (this.data[toolId] !== undefined) {
      tool.setValue(this.data[toolId]);
    }
    
    // 监听工具值变化，自动保存到data对象
    tool.on('change', (value) => {
      this.setData(toolId, value);
    });
  }

  /**
   * 销毁工具球
   */
  destroy() {
    // 保存数据
    this.saveToStorage();
    
    if (this.dragHandler) {
      this.dragHandler.destroy();
    }
    
    if (this.panel) {
      this.panel.destroy();
    }
    
    if (this.container && this.container.parentNode) {
      this.container.parentNode.removeChild(this.container);
    }
    
    this.removeAllListeners();
  }
}

// 继承事件发射器
Object.assign(ToolBall.prototype, EventEmitter.prototype);

  // ==================== 初始化函数 ====================

  /**
   * 初始化工具球
   * @param {Object} config - 配置对象
   * @returns {ToolBall} 工具球实例
   */
  function initToolBall(config = {}) {
  // 创建工具球实例
  const toolBall = new ToolBall();
  
  // 初始化
  toolBall.init(config);
  
  // 显示工具球
  toolBall.show();
  
  return toolBall;
}

  // ==================== 闭包导出 ====================

  // 将API暴露到全局作用域，避免函数污染
  global.ToolBallAPI = {
    initToolBall: initToolBall,
    ToolBall: ToolBall,
    BaseTool: BaseTool,
    ButtonTool: ButtonTool,
    SwitchTool: SwitchTool,
    SelectTool: SelectTool,
    SliderTool: SliderTool,
    TextTool: TextTool,
    EventEmitter: EventEmitter,
    DragHandler: DragHandler,
    ToolPanel: ToolPanel
  };

  // 为了向后兼容，也提供简化的全局函数
  global.initToolBall = initToolBall;

  console.log('ToolBall 组件已加载完成');

})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this);
